package com.webflux.demo.webfluxdemo.controller;

import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.awt.*;
import java.time.Duration;

/**
 * SpringMVC： DispatcherServlet；
 * SpringWebFlux： DispatcherHandler
 * 1、请求处理流程
 * ● HandlerMapping：请求映射处理器； 保存每个请求由哪个方法进行处理
 * ● HandlerAdapter：处理器适配器；反射执行目标方法
 * ● HandlerResultHandler：处理器结果处理器；
 * *
 * SpringMVC： DispatcherServlet 有一个 doDispatch() 方法，来处理所有请求；
 * WebFlux： DispatcherHandler 有一个 handle() 方法，来处理所有请求；
 * <p>
 * ● 1、请求和响应都封装在 ServerWebExchange 对象中，由handle方法进行处理
 * ● 2、如果没有任何的请求映射器； 直接返回一个： 创建一个未找到的错误； 404； 返回Mono.error；终结流
 * ● 3、跨域工具，是否跨域请求，跨域请求检查是否复杂跨域，需要预检请求；
 * ● 4、Flux流式操作，先找到HandlerMapping，再获取handlerAdapter，再用Adapter处理请求，期间的错误由onErrorResume触发回调进行处理；
 * 源码中的核心两个：
 * ● handleRequestWith： 编写了handlerAdapter怎么处理请求
 * ● handleResult： String、User、ServerSendEvent、Mono、Flux ...
 * <p>
 * concatMap： 先挨个元素变，然后把变的结果按照之前元素的顺序拼接成一个完整流
 */
@RestController
public class HelloController {

    @GetMapping("/error")
    public Mono<String> error() {
        return Mono.just(0)
                .map(i -> 10 / i)
                .map(i -> "i=" + i);
    }

    @GetMapping(value = "/sse2", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> sse2() {
        return Flux.range(1, 10)
                .map(i -> {
                    // 构建一个SSE对象
                    return ServerSentEvent.builder("prefix-" + i)
                            .id(i + "")
                            .comment("comment-" + i)
                            .event("event")
                            .build();
                })
                .delayElements(Duration.ofMillis(500));
    }

    // SSE测试
    @GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> sse() {
        return Flux.range(1, 10)
                .map(i -> "item" + i)
                .delayElements(Duration.ofMillis(500));
    }

    @GetMapping("/list")
    public Flux<String> list() {
        return Flux.just("item1", "item2");
    }

    /**
     * 推荐方式
     * 1. 返回单个数据Mono：Mono<Order>,User,String,Map
     * 2. 返回多个数据Flux: Flux<Order>
     * 3. 配合Flux，完成SSE：Server Send Event 服务端时间推送
     *
     * @return
     */
    @GetMapping("/hellohaha")
    public Mono<String> helloNew() {
        return Mono.just("哈哈哈");
    }

    // WebFlux:向下兼容原来SpringMVC的大多数注解和API
    @GetMapping("/hello")
    public String hello(@RequestParam(value = "key", required = false, defaultValue = "world") String key) {
        return "hello, " + key;
    }

}
